package com.lst.api.utils;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.Map.Entry;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.usermodel.Range;
import org.apache.poi.ooxml.POIXMLDocument;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;

import com.lst.api.constant.ContractConstants;
import com.lst.api.exception.RequestParamErrorException;

public class WordUtil {
	
	public static String WORD_TYPE_DOC = "doc";
	public static String WORD_TYPE_DOCX = "docx";
	public static String USER_DIR = System.getProperty("user.dir");
	

    /*public static void main(String[] args) throws Exception{           
        Map<String, Object> param = new HashMap<String, Object>();  
       Map<String,Object> header = new HashMap<String, Object>();  
        header.put("width", 100);  
        header.put("height", 100);  
        header.put("type", "png");  
        header.put("content", "D:\\1.png");  
        param.put("${sign}",header);
        
         
        param.put("${1}$", "左侧段落");
        param.put("${2}$", "text");
        param.put("${3}$", "such");
        param.put("${4}$", "男");
        param.put("${5}$", "2017/08/04");
        param.put("${6}$", "头像.jpg");
        param.put("${7}$", "14584df545656");
        param.put("${8}$", "36°");
        param.put("${9}$", "28mol");
        param.put("${10}$", "36mol");
        param.put("${11}$", "78g");  
        param.put("${date}$", "2018"); 
        
        String readPath = "D:\\test.docx";
	    String writePath = "replace.docx";
        
        
        param.put("${name}", "肖锡标");//姓名
        param.put("${idcard}", "445281199230363557");//身份证号码
        param.put("${loanTransaction}", "秋收贷款业务");//业务名称
        param.put("${loanTypes}", "个人信用贷款、小额企业贷款、企业大额贸易融资、企业流动资金周转贷款");//贷款种类，多个以简体中文"、"隔开
        param.put("${loanAmount}", "100万元");//贷款金额
        param.put("${serviceFee}", "5000元");//服务费
        param.put("${guaranteeFee}", "10万元");//担保费
        param.put("${accountMaintenanceFee}", "1000元");//账户管理费
        param.put("${rishCashDeposit}", "2000元");//风险保证金
        param.put("${channelAgencyFee}", "2000元");//渠道代理费
        param.put("${invoiceFee}", "3000元");//发票费
        param.put("${materialFee}", "100元");//资料费
        param.put("${advanceFundFee}", "4000元");//垫资费
        param.put("${paymentFee}", "800元");//预付金
        param.put("${queryFee}", "50元");//抵押登记、查询费用
        param.put("${mortgageUrgentFee}", "600元");//抵押加急费
        param.put("${downPayment}", "3000元");//预付定金
        param.put("${fullPayment}", "20000元");//全额支付
        param.put("${signDate}", "2020 年 02 月 04日");//签署时间
        //补充说明
        param.put("${content}", "这是补充说明，第十条请注意。这是补充说明，第十条请注意。这是补充说明，第十条请注意。这是补充说明，第十条请注意。这是补充说明，第十条请注意。这是补充说明，第十条请注意。这是补充说明，第十条请注意。这是补充说明，第十条请注意。");
        
        String result = replaceAndGenerateWord(readPath, param, writePath, null, null);         

    }*/
    
    
    public static String replaceAndGenerateWord(String templatePath,String tempFilePath, Map<String, Object> param, String fileName) throws InvalidFormatException, IOException{
    	return replaceAndGenerateWord( templatePath, tempFilePath,  param,  fileName, null, null);
    }
    
    
    public static String replaceAndGenerateWord(String templatePath,String tempFilePath, Map<String, Object> param) throws InvalidFormatException, IOException{
    	return replaceAndGenerateWord( templatePath, tempFilePath,  param,  null, null, null);
    }
    
    /**
     * 替换word中的自定义字符串以及图片（适用于word2003+ 版本）
     * 注：2003版本word不支持替换图片，2007版本以上可以替换图片
     * @param templatePath  模板路径
     * @param tempFilePath	临时文件存放目录
     * @param param			替换参数集合
     * @param fileName		生成文件名称，未传入时自动根据UUID以及模板后缀生成文件名称
     * @param request
     * @param response
     * @return
     * @throws InvalidFormatException
     * @throws IOException
     */
    public static String replaceAndGenerateWord(String templatePath,String tempFilePath, Map<String, Object> param, String fileName, HttpServletRequest request, HttpServletResponse response) throws InvalidFormatException, IOException{
       
    	checkParams(templatePath, tempFilePath);
    	templatePath = USER_DIR + templatePath;
    	String fileType = templatePath.substring(templatePath.lastIndexOf(".") + 1);
    	
    	if(StringUtils.isBlank(fileName)) {
    		fileName = UUID.randomUUID().toString().replace("-", "").concat("." + fileType);
    	}
    	
        //处理docx文档 2007-2013
        if(fileType.equalsIgnoreCase(WORD_TYPE_DOCX)){ 
            CustomXWPFDocument document = null;
            OPCPackage pack = POIXMLDocument.openPackage(templatePath);
            document = new CustomXWPFDocument(pack);  
            if (param != null && param.size() > 0) {   
                //处理段落  
                List<XWPFParagraph> paragraphList = document.getParagraphs();  
                processParagraphs(paragraphList, param, document);                    
                //处理表格  
                Iterator<XWPFTable> it = document.getTablesIterator();  
                while (it.hasNext()) {  
                    XWPFTable table = it.next();  
                    List<XWPFTableRow> rows = table.getRows();  
                    for (XWPFTableRow row : rows) {  
                        List<XWPFTableCell> cells = row.getTableCells();  
                        for (XWPFTableCell cell : cells) {  
                            List<XWPFParagraph> paragraphListTable =  cell.getParagraphs();  
                            processParagraphs(paragraphListTable, param, document);  
                        }  
                    }  
                } 
                
                createDir(tempFilePath);
                FileOutputStream fos = new FileOutputStream(new File(tempFilePath.concat(fileName)));
                document.write(fos);
                fos.flush();
                fos.close();
                return tempFilePath.concat(fileName);
            }
        //处理doc文档 97-2003
        }else if(fileType.equalsIgnoreCase(WORD_TYPE_DOC)){
            HWPFDocument document = null;   
            document = new HWPFDocument(new FileInputStream(templatePath));  
            Range range = document.getRange();  
            for (Map.Entry<String, Object> entry : param.entrySet()) {
                Object value = entry.getValue();
                if(value instanceof String){
                    range.replaceText(entry.getKey(), entry.getValue().toString()); 
                }else if(value instanceof Map){
                    //TODO word2003暂时不能处理图片
                }
            }
            createDir(tempFilePath);
            FileOutputStream fos = new FileOutputStream(new File(tempFilePath.concat(fileName)));
            document.write(fos);
            fos.flush();
            fos.close();
            doExport(fileName, tempFilePath.concat(fileName), request, response);
            return tempFilePath.concat(fileName);
        }                                       
        return null;
    }

    /** 
     * 处理段落 
     * @param paragraphList 
     * @throws FileNotFoundException 
     * @throws InvalidFormatException 
     */  
    public static void processParagraphs(List<XWPFParagraph> paragraphList,Map<String, Object> param,CustomXWPFDocument doc) throws InvalidFormatException, FileNotFoundException{  
        if(paragraphList != null && paragraphList.size() > 0){   
            //首选循环段落
            for(XWPFParagraph paragraph:paragraphList){ 
                //获取段落的text
                List<XWPFRun> runs = paragraph.getRuns();
                for (XWPFRun run : runs) {
                	String text = run.getText(0);
                	if(text != null){
                        for (Entry<String, Object> entry : param.entrySet()) {  
                            String key = entry.getKey();                       
                            Object value = entry.getValue();
                            if(text.indexOf(key) != -1){
                            	//替换                      
                                if(value instanceof String){
                                    String text2 = text.replace(key, value.toString());
                                    run.setText(text2,0);
                                }else if(value instanceof Map){
                                    if(text.indexOf(key) != -1){
                                    	run.setText("",0);
                                        String imgurl = (String)((Map<?, ?>) value).get(ContractConstants.SIGN_URL_NAME);
                                        FileInputStream fis = (FileInputStream)((Map<?, ?>) value).get(ContractConstants.SIGN_FIS_NAME);
                                        if(fis == null && StringUtils.isNotBlank(imgurl)) {
                                        	fis = new FileInputStream(new File(imgurl));
                                        }
                                        
                                        String type = (String)((Map<?, ?>) value).get(ContractConstants.SIGN_TYPE_NAME);
                                        int width = (Integer) ((Map<?, ?>) value).get(ContractConstants.SIGN_WIDTH_NAME);
                                        int height = (Integer) ((Map<?, ?>) value).get(ContractConstants.SIGN_HEIGHT_NAME);
                                        String blipId = doc.addPictureData(fis, getPictureType(type));
                                        doc.createPicture(run,blipId,doc.getNextPicNameNumber(getPictureType(type)), width, height,paragraph);                          
                                    }
                                }
                            }
                        }  
                    }
				}
            }  
        }  
    }  

    /** 
     * 根据图片类型，取得对应的图片类型代码 
     * @param picType 
     * @return int 
     */  
    private static int getPictureType(String picType){  
        int res = CustomXWPFDocument.PICTURE_TYPE_PICT;  
        if(picType != null){
            if(picType.equalsIgnoreCase("png")){  
                res = CustomXWPFDocument.PICTURE_TYPE_PNG;  
            }else if(picType.equalsIgnoreCase("dib")){  
                res = CustomXWPFDocument.PICTURE_TYPE_DIB;  
            }else if(picType.equalsIgnoreCase("emf")){  
                res = CustomXWPFDocument.PICTURE_TYPE_EMF;  
            }else if(picType.equalsIgnoreCase("jpg") || picType.equalsIgnoreCase("jpeg")){  
                res = CustomXWPFDocument.PICTURE_TYPE_JPEG;  
            }else if(picType.equalsIgnoreCase("wmf")){  
                res = CustomXWPFDocument.PICTURE_TYPE_WMF;  
            }  
        }  
        return res;  
    }  

    /**
     * 导出
     * 
     * @param fileName
     * @param filePath
     * @param request
     * @param response
     */
    public static void doExport(String fileName, String filePath, HttpServletRequest request, HttpServletResponse response){
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        File file = null;
        try {
          file = new File(filePath);
          request.setCharacterEncoding("UTF-8");
          String agent = request.getHeader("User-Agent").toUpperCase();
          if ((agent.indexOf("MSIE") > 0) || ((agent.indexOf("RV") != -1) && (agent.indexOf("FIREFOX") == -1)))
              fileName = URLEncoder.encode(fileName, "UTF-8");
          else {
              fileName = new String(fileName.getBytes("UTF-8"), "ISO8859-1");
          }
          response.setContentType("application/x-msdownload;");
          response.setHeader("Content-disposition", "attachment; filename=" + fileName);
          response.setHeader("Content-Length", String.valueOf(file.length()));
          bis = new BufferedInputStream(new FileInputStream(file));
          bos = new BufferedOutputStream(response.getOutputStream());

          byte[] buff = new byte[2048];
          int bytesRead;
          while (-1 != (bytesRead = bis.read(buff, 0, buff.length)))
            bos.write(buff, 0, bytesRead);
        }
        catch (Exception e) {
//          System.out.println("导出文件失败！");
        } finally {
          try {
            if (bis != null) {
              bis.close();
            }
            if (bos != null) {
              bos.close();
            }
            file.delete();
          } catch (Exception e) {
//            LOGGER.error("导出文件关闭流出错！", e);
          }
        }
    } 

    /**
     * 创建目录
     * @param basePath
     */
    public static void createDir(String basePath){
      File file = new File(basePath);
      if (!file.exists())
        file.mkdirs();
    }
    
    /**
     * 检查参数
     * @param templatePath
     * @param tempFilePath
     */
    public static void checkParams(String templatePath,String tempFilePath){
    	 if (StringUtils.isBlank(templatePath)) {
             throw new RequestParamErrorException("【文件创建】模板文件不能为空！");
         }
    	 
    	 String fileType = templatePath.substring(templatePath.lastIndexOf(".") + 1);
    	 if(!WORD_TYPE_DOC.equalsIgnoreCase(fileType) && !WORD_TYPE_DOCX.equalsIgnoreCase(fileType)) {
    		 throw new RequestParamErrorException("【文件创建】模板文件格式不是word文件！");
    	 }
    	 
    	 if (StringUtils.isBlank(tempFilePath)) {
             throw new RequestParamErrorException("【文件创建】文件临时存放目录不能为空！");
         }
    }
}
